package net.njcp.icodes.builder;

import net.njcp.icodes.bo.Configuration;
import net.njcp.icodes.bo.Parser;
import net.njcp.icodes.io.Resources;
import net.njcp.icodes.parsing.XNode;
import net.njcp.icodes.parsing.XPathParser;
import net.njcp.icodes.util.PackageUtil;

import java.io.IOException;
import java.io.Reader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ClassName XMLConfigBuilder
 * @Description: TODO
 * @Author 柳拓
 * @Date 2019/8/16
 * @Version V1.0
 **/
public class XMLConfigBuilder {

    private final XPathParser parser;
    private final Configuration configuration;

    public XMLConfigBuilder(Reader reader) {
        this(new XPathParser(reader, false, null, null));
    }

    private XMLConfigBuilder(XPathParser parser){
        this.parser = parser;
        configuration = new Configuration();
    }

    public Configuration parse() {
        //解析config.xml
        parseConfiguration();
        return configuration;
    }

    public void parseConfiguration(){
        //解析Aliases别名集合
        parserAliases(parser.evalNode("/config/typeAliases"));
        //解析selectors数据解析器集合
        parserSelectorses(parser.evalNode("/config/selectorses"));
        //解析parsers集合
        parserParsers(parser.evalNode("/config/parsers"));
    }

    public void parserAliases(XNode node){
        if(node != null){
            List<XNode> xNodes = node.getChildren();
            for (XNode xnode:xNodes) {
                parserAlias(xnode);
            }
        }
    }

    public void parserAlias(XNode node){
        String alias = node.getStringAttribute("alias");
        if(alias != null){
            configuration.registerAliases(alias, node.getStringAttribute("type"));
        }else {
            if (node.getName().equals("package")){
                String packageName = node.getStringAttribute("name");
                List<String> classNames = PackageUtil.getClassName(packageName);
                if (classNames != null) {
                    for (String className : classNames) {
                        configuration.registerAliases(PackageUtil.getName(className), className);
                    }
                }
            }
        }
    }

    public void parserSelectorses(XNode node){
        if(node != null){
            List<XNode> xNodes = node.getChildren();
            for (XNode xnode:xNodes) {
                parserSelectors(xnode);
            }
        }
    }

    public void parserSelectors(XNode node){
        String namespace = node.getStringAttribute("namespace");
        Map<String, String> selectors = parserSelector(node);
        configuration.registerSelectors(namespace, selectors);
    }

    public Map<String, String> parserSelector(XNode node){
        List<XNode> xNodes = node.getChildren();
        Map<String, String> map = new HashMap<>();
        for (XNode xNode:xNodes) {
            String code = xNode.getStringAttribute("code");
            String value = xNode.getStringAttribute("value");
            map.put(code, value);
        }
        return map;
    }


    public void parserParsers(XNode node){
        if(node.getStringAttribute("package")!=null){
            List<String> xmlNames = PackageUtil.getClassName(node.getStringAttribute("package"));
            for (String xmlName : xmlNames) {
                parseParser(xmlName);
            }
        }else {
            List<XNode> xNodes = node.getChildren();
            for (XNode xnode : xNodes) {
                parseParser(xnode.getStringAttribute("resource"));
            }
        }
    }

    public void parseParser(String resource){

        Reader reader = null;
        try {
            reader = Resources.getResourceAsReader(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }

        XmlParserBuilder xmlParserBuilder = new XmlParserBuilder(reader,configuration);
        xmlParserBuilder.parse();
    }
    public Parser getParser(String namespace){
        return configuration.getParser(namespace);
    }


}
